home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / SMTPSUBR.C < prev    next >
Text File  |  1993-10-14  |  16KB  |  752 lines

  1. #include <ctype.h>
  2. #include <conio.h>
  3. #include <io.h>
  4. #include "global.h"
  5. #include "config.h"
  6. #include "socket.h"
  7. #include "smtp.h"
  8. #include "domain.h"
  9. #include "files.h"
  10. #include "iface.h"
  11. #include "server.h"
  12.  
  13. #ifdef MAILBOX
  14. #include "bbs.h"
  15. #endif
  16.  
  17. #ifdef NNTP
  18. #include "nntp.h"
  19. #endif
  20.  
  21. int32 Gateway = 0;
  22.  
  23. static char *Days[7] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  24. char *Months[12] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  25.  
  26. char *Hdrs[] = {
  27.     "Approved: ",
  28.     "From: ",
  29.     "To: ",
  30.     "Date: ",
  31.     "Message-Id: ",
  32.     "Subject: ",
  33.     "Received: ",
  34.     "Sender: ",
  35.     "Reply-To: ",
  36.     "Status: ",
  37.     "X-BBS-Msg-Type: ",
  38.     "X-Forwarded-To: ",
  39.     "Cc: ",
  40.     "Return-Receipt-To: ",
  41.     "Apparently-To: ",
  42.     "Errors-To: ",
  43.     "Organization: ",
  44.     "Bulletin-Id: ",
  45.     "Expires: ",
  46.     "Path: ",
  47.     "Newsgroups: ",
  48.     "Distribution: ",
  49.     NULLCHAR
  50. };
  51.  
  52. /* return the header type */
  53. #ifdef NNTP
  54. int
  55. #else
  56. static int
  57. #endif
  58. htype(char *s)
  59. {
  60.     char i, *p = s;
  61.  
  62.     /* check to see if there is a ':' before and white space */
  63.     while (*p != '\0' && *p != ' ' && *p != ':') {
  64.         p++;
  65.     }
  66.     if(*p != ':') {
  67.         return NOHEADER;
  68.     }
  69.     for(i = 0; Hdrs[i] != NULLCHAR; i++) {
  70.         if(strnicmp(Hdrs[i],s,strlen(Hdrs[i])) == 0) {
  71.             return i;
  72.         }
  73.     }
  74.     return UNKNOWN;
  75. }
  76.  
  77. /* Mail routing function. For now just use the hosts file */
  78. int32
  79. mailroute(char *dest)
  80. {
  81.     /*
  82.      * Look up address or use the gateway.
  83.      * Gateway must be initialized at the top of this file !!
  84.      *
  85.      */
  86.     int32 destaddr;
  87.  
  88.     if((destaddr = resolve(dest)) != 0) {
  89.         return destaddr;
  90.     }
  91.     return Gateway;
  92. }
  93.  
  94. /* add an element to the front of the list pointed to by head
  95.  */
  96. struct list *
  97. addlist(struct list **head,char *val,int type)
  98. {
  99.     struct list *tp = mxallocw(sizeof(struct list));
  100.  
  101.     tp->type = type;
  102.     tp->val = strxdup(val);
  103.  
  104.     /* add entry to front of existing list */
  105.     if(*head != NULLLIST) {
  106.         tp->next = *head;
  107.     }
  108.     *head = tp;
  109.  
  110.     return tp;
  111. }
  112.  
  113. /* delete a list of list structs */
  114. void
  115. del_list(struct list *lp)
  116. {
  117.     struct list *tp, *tp1 = NULLLIST;
  118.  
  119.     for(tp = lp; tp != NULLLIST; tp = tp1) {
  120.         tp1 = tp->next;
  121.         xfree(tp->val);
  122.         xfree(tp);
  123.     }
  124. }
  125.  
  126. /* Return Date/Time in Arpanet format in passed string */
  127. char *
  128. rfc822_date(int32 *t)
  129. {
  130.     char *p;
  131.     static char str[40], tz[5];
  132.  
  133.     /* Read the system time */
  134.     struct tm *ltm = localtime(t);            /* dg1zx */
  135.  
  136.     if ((p = getenv("TZ")) == NULL) {
  137.         strcpy(tz," UTC");
  138.     } else {
  139.         sprintf(tz," %.3s",p);
  140.     }
  141.     /* rfc 822 format */
  142.     sprintf(str,"%s, %02d %s %02d %02d:%02d:%02d%.4s\n",
  143.         Days[ltm->tm_wday],
  144.         ltm->tm_mday,
  145.         Months[ltm->tm_mon],
  146.         ltm->tm_year,
  147.         ltm->tm_hour,
  148.         ltm->tm_min,
  149.         ltm->tm_sec,
  150.         tz);
  151.  
  152.     return str;
  153. }
  154.  
  155. long
  156. get_msgid(void)
  157. {
  158.     char sfilename[MAXPATH];
  159.     long sequence = 0;
  160.     FILE *sfile;
  161.  
  162.     sprintf(sfilename,"%s/sequence.seq",Mailqdir);
  163.  
  164.     /* if sequence file exists, get the value, otherwise set it */
  165.     if((sfile = Fopen(sfilename,READ_TEXT,0,0)) != NULLFILE) {
  166.         /* two digits more than required */
  167.         char s[10];
  168.  
  169.         fgets(s,10,sfile);
  170.         sequence = atol(s);
  171.  
  172.         /* Keep it in range of and 8 digit number to use for dos name prefix. */
  173.         if(sequence < 0L || sequence > 99999999L) {
  174.             sequence = 0;
  175.         }
  176.         Fclose(sfile);
  177.     }
  178.     /* increment sequence number, and write to sequence file */
  179.     sequence++;
  180.  
  181.     if((sfile = Fopen(sfilename,WRITE_TEXT,0,1)) != NULLFILE) {
  182.         fprintf(sfile,"%ld",sequence);
  183.         Fclose(sfile);
  184.     }
  185.     return sequence;
  186. }
  187.  
  188. /* Given a string of the form <user@host>, extract the part inside the
  189.  * brackets and return a pointer to it.
  190.  */
  191. char *
  192. getname(char *cp)
  193. {
  194.     char *cp1;
  195.  
  196.     if((cp = strchr(cp,'<')) == NULLCHAR) {
  197.         return NULLCHAR;
  198.     }
  199.     if((cp1 = strchr(++cp,'>')) == NULLCHAR) {
  200.         return NULLCHAR;
  201.     }
  202.     *cp1 = '\0';
  203.  
  204.     return cp;
  205. }
  206.  
  207. /* test if mail address is valid */
  208. int
  209. validate_address(char *s)
  210. {
  211.     char *cp;
  212.     int perms;
  213.  
  214.     /* if first character in address is a bang (!) address is NNTP_GATE
  215.      * dk5dc */
  216.     if(*s == '!') {
  217. #ifdef NNTP
  218.         return NNTP_GATE;
  219. #else
  220.         goto badaddr;
  221. #endif
  222.     }
  223.     /* if address has @ in it the check dest address */
  224.     if((cp = strrchr(s,'@')) != NULLCHAR) {
  225.         int32 addr = 0;
  226.         cp++;
  227.  
  228.         /* 1st check if its our hostname
  229.          * if not then check the hosts file and see
  230.          * if we can resolve ther address to a know site
  231.          * or one of our aliases
  232.          */
  233.         if(strcmp(cp,Hostname) != 0) {
  234.             if((addr = mailroute(cp)) == 0 && Smtpmode == ROUTE) {
  235.                 goto badaddr;
  236.             }
  237.             if(ismyaddr(addr) == NULLIF) {
  238.                 return DOMAIN;
  239.             }
  240.         }
  241.         /* on a local address remove the host name part */
  242.         *--cp = '\0';
  243.     }
  244.     /* if using an external router leave address alone */
  245.     if(Smtpmode == QUEUE) {
  246.         return LOCAL;
  247.     }
  248.     /* check for the user%host hack */
  249.     if((cp = strrchr(s,'%')) != NULLCHAR) {
  250.         *cp++ = '@';
  251.  
  252.         /* reroute based on host name following the % seperator */
  253.         if(mailroute(cp) == 0) {
  254.             goto badaddr;
  255.         } else {
  256.             return DOMAIN;
  257.         }
  258.     }
  259.     if(chkbaddoschars(s)) {
  260.         goto badaddr;
  261.     }
  262.     return LOCAL;
  263.  
  264. badaddr:
  265.     if((perms = userlogin(IPPORT_SMTP,0,s)) == 0) {
  266.         if((perms = Smtpbbs) == 0) {
  267.             perms = MAIL;
  268.         }
  269.     }
  270.     if(perms == BBS || perms == NEWS) {
  271.         return LOCAL;
  272.     }
  273.     return BADADDR;
  274.  
  275. }
  276.  
  277. #define SKIPWORD(X) while(*X && *X != ' ' && *X != '\t' && *X != '\n' && *X != ',') X++;
  278. #define SKIPSPACE(X) while(*X == ' ' || *X == '\t' || *X == '\n' || *X == ',') X++;
  279.  
  280. /* check for an alias and expand alias into a address list */
  281. struct list *
  282. expandalias(struct list **head,char *user)
  283. {
  284.     FILE *fp;
  285.     int inalias = 0;
  286.     struct list *tp = NULLLIST;
  287.     char *s, *p, buf[LINELEN];
  288.  
  289.     if((fp = Fopen(Alias,READ_TEXT,0,0)) == NULLFILE) {
  290.         /* No alias file found, try to resolve M* domain name records */
  291.         if((s = resolve_mailb(user)) != NULLCHAR) {
  292.             /* remove the trailing dot */
  293.             int len = strlen(s) - 1;
  294.  
  295.             if(s[len] == '.') {
  296.                 s[len] = '\0';
  297.             }
  298.             /* replace first dot with @ if there is no @ */
  299.             if(strchr(s,'@') == NULLCHAR && (p = strchr(s,'.')) != NULLCHAR) {
  300.                 *p = '@';
  301.             }
  302.             return addlist(head,s,(strchr(s,'@') != NULLCHAR) ? DOMAIN : LOCAL);
  303.         }
  304.         return addlist(head,user,LOCAL);
  305.     }
  306.     while(fgets(buf,LINELEN,fp) != NULLCHAR) {
  307.         p = buf;
  308.         if(*p == '#' || *p == '\0') {
  309.             continue;
  310.         }
  311.         rip(p);
  312.  
  313.         /* if not in an matching entry skip continuation lines */
  314.         if(!inalias && isspace(*p)) {
  315.             continue;
  316.         }
  317.         /* when processing an active alias check for a continuation */
  318.         if(inalias) {
  319.             if(!isspace(*p)) {
  320.                 break;    /* done */
  321.             }
  322.         } else {
  323.             s = p;
  324.             SKIPWORD(p);
  325.  
  326.             *p++ = '\0';    /* end the alias name */
  327.  
  328.             if(strcmp(s,user) != 0) {
  329.                 continue;    /* no match go on */
  330.             }
  331.             inalias = 1;
  332.         }
  333.  
  334.         /* process the recipients on the alias line */
  335.         SKIPSPACE(p);
  336.  
  337.         while(*p != '\0' && *p != '#') {
  338.             char flag = LOCAL;
  339.  
  340.             s = p;
  341.             SKIPWORD(p);
  342.  
  343.             if(*p != '\0') {
  344.                 *p++ = '\0';
  345.             }
  346.             /* find hostname */
  347.             if(strchr(s,'@') != NULLCHAR) {
  348.                 flag = DOMAIN;
  349.             }
  350. #ifdef NNTP
  351.             /* a bang overrides a DOMAIN address */
  352.             if(*s == '!') {
  353.                 flag = NNTP_GATE;
  354.             }
  355. #endif
  356.             tp = addlist(head,s,flag);
  357.  
  358.             SKIPSPACE(p);
  359.         }
  360.     }
  361.     Fclose(fp);
  362.  
  363.     return inalias ? tp : addlist(head,user,LOCAL);
  364. }
  365.  
  366. /* place a mail job in the outbound queue or deliver to the appr. mailbox */
  367. static int near
  368. queuejob(FILE *data,char *from,struct list *to,char *host)
  369. {
  370.     FILE *fp;
  371.     int32 msgid = get_msgid();
  372.     char fstring[MAXPATH], *Qdir = host ? Mailqdir : Routeqdir;
  373.  
  374.     sprintf(fstring,"%s/%ld.txt",Qdir,msgid);
  375.  
  376.     if((fp = Fopen(fstring,WRITE_TEXT,0,1)) != NULLFILE) {
  377.         char buf[LINELEN];
  378.  
  379.         rewind(data);
  380.  
  381.         while(fgets(buf,LINELEN,data) != NULL) {
  382.             fputs(buf,fp);
  383.         }
  384.         Fclose(fp);
  385.  
  386.         sprintf(fstring,"%s/%ld.wrk",Qdir,msgid);
  387.  
  388.         if((fp = Fopen(fstring,WRITE_TEXT,0,1)) != NULLFILE) {
  389.             struct list *ap;
  390.  
  391.             if(host) {
  392.                 fprintf(fp,"%s\n%s\n",host,from);
  393.             } else {
  394.                 fprintf(fp,"From: %s\n",from);
  395.             }
  396.             for(ap = to; ap != NULLLIST; ap = ap->next) {
  397.                 fprintf(fp,"%s%s\n",host ? "" : "To: ",ap->val);
  398.  
  399.                 log(-1,IPPORT_SMTP,"%cqueue job %ld To: %s From: %s",
  400.                     host ? 'm' : 'r',msgid,ap->val,from);
  401.             }
  402.             Fclose(fp);
  403.             return 0;
  404.         }
  405.     }
  406. quit:
  407.     Fclose(fp);
  408.     return 1;
  409. }
  410.  
  411. /* Parse a string in the "Text: <user@host>" or "Text: user@host (Text)"
  412.  * format for the address user@host.
  413.  */
  414. static char * near
  415. getaddress(char *string,int cont)
  416. /* int cont;        /* true if string is a continued header line */
  417. {
  418.     char *cp, *ap = NULLCHAR;
  419.     int par = 0;
  420.  
  421.     /* Look for <> style address */
  422.     if((cp = getname(string)) != NULLCHAR) {
  423.          return cp;
  424.     }
  425.     cp = string;
  426.  
  427.     if(!cont) {
  428.         /* Skip the token */
  429.         if((cp = strchr(string,':')) == NULLCHAR) {
  430.             return NULLCHAR;
  431.         } else {
  432.             ++cp;
  433.         }
  434.     }
  435.     for(; *cp != '\0'; ++cp) {
  436.         if(par && *cp == ')') {
  437.             --par;
  438.             continue;
  439.         }
  440.         /* Ignore text within parenthesis */
  441.         if(*cp == '(') {
  442.             ++par;
  443.         }
  444.         if(par) {
  445.             continue;
  446.         }
  447.         if(*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ',') {
  448.             if(ap != NULLCHAR) {
  449.                 break;
  450.             }
  451.             continue;
  452.         }
  453.         if(ap == NULLCHAR) {
  454.           ap = cp;
  455.         }
  456.     }
  457.     *cp = '\0';
  458.     return ap;
  459. }
  460.  
  461. /* Mailer daemon return mail mechanism */
  462. int
  463. mdaemon(
  464. FILE *data,            /* pointer to rewound data file */
  465. char *to,            /* Overridden by Errors-To: line if bounce is true */
  466. struct list *lp,    /* error log for failed mail */
  467. int bounce)            /* True for failed mail, otherwise return receipt */
  468. {
  469.     FILE *tfile;
  470.     char buf[LINELEN], *cp, *newto = NULLCHAR;
  471.     int address_type;
  472.  
  473.     if(to == NULLCHAR || (to != NULLCHAR && *to == '\0') || bounce) {
  474.         while(fgets(buf,LINELEN,data) != NULLCHAR) {
  475.             if(*buf == '\n') {
  476.                 break;
  477.             }
  478.             /* Look for Errors-To: */
  479.             if(htype(buf) == ERRORSTO && (cp = getaddress(buf,0)) != NULLCHAR) {
  480.                 if(newto != NULLCHAR) {
  481.                     xfree(newto);
  482.                 }
  483.                 newto = strxdup(cp);
  484.                 break;
  485.             }
  486.         }
  487.         if(newto == NULLCHAR
  488.           && ((to != NULLCHAR && *to == '\0') || to == NULLCHAR)) {
  489.             return -1;
  490.         }
  491.         rewind(data);
  492.     }
  493.     if((tfile = Tmpfile(0,1)) == NULLFILE) {
  494.         return -1;
  495.     }
  496.     if(newto == NULLCHAR) {
  497.         newto = strxdup(to);
  498.     }
  499.     fprintf(tfile,"%s%s%s<%ld@%s>\n",
  500.         Hdrs[DATE],
  501.         rfc822_date(&currtime),
  502.         Hdrs[MSGID],
  503.         get_msgid(),
  504.         Hostname);
  505.     fprintf(tfile,"%sMAILER-DAEMON@%s (Mail Delivery Subsystem)\n",
  506.         Hdrs[FROM],Hostname);
  507.     fprintf(tfile,"%s%s\n%s%s\n\n",
  508.         Hdrs[TO],
  509.         newto,
  510.         Hdrs[SUBJECT],
  511.         bounce ? "Failed mail" : "Return receipt");
  512.  
  513.     if(bounce) {
  514.         fputs("   ==== Transcript follows ====\n\n",tfile);
  515.  
  516.         for (; lp != NULLLIST; lp = lp->next) {
  517.             fprintf(tfile,"%s\n",lp->val);
  518.         }
  519.         fputs("\n   ==== Unsent message follows ====\n\n",tfile);
  520.     } else {
  521.         fputs("   ==== Message header follows ====\n",tfile);
  522.     }
  523.     while(fgets(buf,LINELEN,data) != NULLCHAR) {
  524.         if(*buf == '\n') {
  525.             break;
  526.         }
  527.         fputs(buf,tfile);
  528.     }
  529.     if(bounce) {
  530.         fputc('\n',tfile);
  531.  
  532.         while(fgets(buf,LINELEN,data)) {
  533.             fputs(buf,tfile);
  534.         }
  535.     }
  536.     rewind(tfile);
  537.  
  538.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  539.     /* check if address is ok */
  540.     if((address_type = validate_address(to)) != BADADDR) {
  541.         struct list *tolist = NULLLIST;
  542.  
  543.         /* if a local address check for an alias */
  544.         if(address_type == LOCAL) {
  545.             expandalias(&tolist,newto);
  546.         } else {
  547.             /* a remote address is added to the list */
  548.             addlist(&tolist,newto,address_type);
  549.         }
  550.         mailit(tfile,"",tolist);
  551.         del_list(tolist);
  552.     }
  553.     Fclose(tfile);
  554.     xfree(newto);
  555.     return 0;
  556. }
  557.  
  558. /* General mailit function. It takes a list of addresses which have already
  559.  * been verified and expanded for aliases. Base on the current mode the message
  560.  * is place in an mbox, the outbound smtp queue or the rqueue interface
  561.  */
  562. int
  563. mailit(FILE *data,char *from,struct list *tolist)
  564. {
  565.     struct list *ap, *dlist = NULLLIST;
  566.     char *cp, *host = NULLCHAR, *qhost, line[LINELEN], *to = NULLCHAR;
  567.     int fail = 0;
  568.     int16 perms = 0;
  569.  
  570.     if(Smtpmode == QUEUE) {
  571.         return queuejob(data,from,tolist,NULLCHAR);
  572.     }
  573.  
  574.     do {
  575.         qhost = NULLCHAR;
  576.  
  577.         for(ap = tolist; ap != NULLLIST; ap = ap->next) {
  578.             if(ap->type == DOMAIN) {
  579.                 if((host = strrchr(ap->val,'@')) != NULLCHAR) {
  580.                     host++;
  581.                 } else {
  582.                     host = Hostname;
  583.                 }
  584.                 if(qhost == NULLCHAR) {
  585.                     qhost = host;
  586.                 }
  587.                 if(stricmp(qhost,host) == 0) {
  588.                     ap->type = BADADDR;
  589.                     addlist(&dlist,ap->val,0);
  590.                 }
  591.             }
  592.         }
  593.         if(qhost != NULLCHAR) {
  594.             rewind(data);
  595.             queuejob(data,from,dlist,qhost);
  596.             del_list(dlist);
  597.             dlist = NULLLIST;
  598.         }
  599.     } while(qhost != NULLCHAR);
  600.  
  601.     for(ap = tolist; ap != NULLLIST; ap = ap->next) {
  602. #ifdef NNTP
  603.         /*-------------------------------------------------------------------*
  604.          * dk5dc, process nntp entries !xxxx....                             *
  605.          *-------------------------------------------------------------------*/
  606.         if(ap->type == NNTP_GATE) {
  607.             nnGpost(data,from,ap);
  608.             ap->type = DOMAIN;
  609.             continue;
  610.         }
  611. #endif
  612.         if(ap->type != LOCAL) {
  613.             ap->type = DOMAIN;
  614.             continue;
  615.         }
  616.         rewind(data);
  617.  
  618.         /* strip off host name of LOCAL addresses
  619.          * only if the host name is equal our Hostname
  620.          */
  621.         if((cp = strchr(ap->val,'@')) != NULLCHAR) {
  622.             if(strstr(Hostname,cp)) {
  623.                 *cp = '\0';
  624.             }
  625.         }
  626.         host = NULLCHAR;
  627.  
  628.         while(fgets(line,LINELEN,data)) {
  629.             rip(line);
  630.  
  631.             if(!*line) {
  632.                 break;
  633.             }
  634.             if(htype(line) == TO) {
  635.                 if(to != NULLCHAR) {
  636.                     xfree(to);
  637.                 }
  638.                 to = strxdup(&line[strlen(Hdrs[TO])]);
  639.                 break;
  640.             }
  641.         }
  642.         rewind(data);
  643.  
  644.         if((perms = userlogin(IPPORT_SMTP,0,to)) == 0) {
  645.             if((perms = Smtpbbs) == 0) {
  646.                 perms = MAIL;
  647.             }
  648.         }
  649.         xfree(to);
  650.  
  651.         while(perms != 0) {
  652.             fail = 0;
  653.             rewind(data);
  654.  
  655.             if(perms & NEWS) {
  656.                 perms ^= NEWS;
  657.                 continue;
  658.             }
  659.             if(perms & BBS) {
  660.                 /* deliver to dk5sg-bbs */
  661.                 fail = recv_from_mail_or_news(data,from,ap->val);
  662.                 perms ^= BBS;
  663.             }
  664.             if(perms & MAIL) {
  665.                 if(mlock(Mailspool,ap->val)) {
  666.                     /* if mail file is busy save it in our smtp queue
  667.                      * and let the smtp daemon try later.
  668.                      */
  669.                     addlist(&dlist,ap->val,0);
  670.                     fail = queuejob(data,Hostname,dlist,from);
  671.                     del_list(dlist);
  672.                     dlist = NULLLIST;
  673.                 } else {
  674.                     FILE *fp;
  675.                     char buf[LINELEN];
  676.                     int tocnt = 0;
  677.  
  678.                     sprintf(buf,"%s/%.8s.txt",
  679.                         Mailspool,chkbaddoschars(ap->val) ? "junk" : ap->val);
  680.  
  681.                     if((fp = Fopen(buf,APPEND_TEXT,0,0)) != NULLFILE) {
  682.                         fprintf(fp,"From %s %s",from,rfc822_date(&currtime));
  683.                         host = NULLCHAR;
  684.  
  685.                         while(fgets(buf,LINELEN,data) != NULLCHAR) {
  686.                             if(*buf == '\n') {
  687.                                 if(tocnt == 0) {
  688.                                     fprintf(fp,"%s%s\n",Hdrs[APPARTO],ap->val);
  689.                                 }
  690.                                 fputc('\n',fp);
  691.                                 break;
  692.                             }
  693.                             fputs(buf,fp);
  694.                             rip(buf);
  695.  
  696.                             switch(htype(buf)){
  697.                             case TO:
  698.                             case CC:
  699.                                 ++tocnt;
  700.                                 break;
  701.                             case RRECEIPT:
  702.                                 if((cp = getaddress(buf,0)) != NULLCHAR) {
  703.                                     if(host != NULLCHAR) {
  704.                                         xfree(host);
  705.                                     }
  706.                                     host = strxdup(cp);
  707.                                 }
  708.                                 break;
  709.                             }
  710.                         }
  711.                         while(fgets(buf,LINELEN,data)) {
  712.                             fputs(buf,fp);
  713.                         }
  714.                         if(ferror(fp)) {
  715.                             fail = 1;
  716.                         } else {
  717.                             fputs("\n",fp);
  718.                         }
  719.                         /* Leave a blank line between msgs */
  720.                         Fclose(fp);
  721.                     }
  722.                     rmlock(Mailspool,ap->val);
  723.                 }
  724.                 perms ^= MAIL;
  725.             }
  726.             if(fail) {
  727.                 return fail;
  728.             }
  729.             if(host != NULLCHAR) {
  730.                 /* Send return receipt */
  731.                 rewind(data);
  732.                 mdaemon(data,host,NULLLIST,0);
  733.                 xfree(host);
  734.             }
  735.             switch(Smtpquiet) {
  736.             case 0:
  737.                 putch(7);
  738.             case 1:
  739.                 /* timestamp by dc3sn */
  740.                 tprintf("SMTP: new mail for %s from %s at %s\n",
  741.                     ap->val,from,timestr(currtime));
  742.                 break;
  743.             case 3:
  744.                 log(-1,IPPORT_SMTP,"SMTP new mail from %s",from);
  745.                     break;
  746.             }
  747.             log(-1,IPPORT_SMTP,"deliver: To: %s From: %s",ap->val,from);
  748.         }
  749.     }
  750.     return fail;
  751. }
  752.